#include "ImageProcessor.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QImageReader>
#include <QUrl>

ImageProcessor::ImageProcessor(QObject *parent) : QObject(parent)
{
}

EdgeDetectionProvider::EdgeDetectionProvider(ImageProcessor *processor) 
    : QQuickImageProvider(QQuickImageProvider::Image), m_processor(processor)
{
}

QImage EdgeDetectionProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    Q_UNUSED(requestedSize)
    
    QString path = id;
    qDebug() << "Image request ID:" << id;
    
    // Handle local file paths
    if (path.startsWith("file://")) {
        path = QUrl(path).toLocalFile();
        qDebug() << "Converted local file path:" << path;
        
        if (!QFile::exists(path)) {
            qWarning() << "File does not exist:" << path;
            return QImage();
        }
        
        QImage result = m_processor->detectEdges(path);
        if (size) *size = result.size();
        return result;
    }
    
    // Handle resource paths
    if (path.startsWith("qrc:")) {
        path = ":" + path.mid(4);
        qDebug() << "Converted resource path:" << path;
    }
    
    // Check if file exists
    if (!QFile::exists(path)) {
        qWarning() << "File does not exist:" << path;
        return QImage();
    }
    
    QImage result = m_processor->detectEdges(path);
    if (size) *size = result.size();
    return result;
}

QImage ImageProcessor::detectEdges(const QString &imagePath)
{
    qDebug() << "Edge detection requested for:" << imagePath;
    
    // Handle both resource paths and local file paths
    QString loadPath = imagePath;
    if (imagePath.startsWith("file://")) {
        loadPath = QUrl(imagePath).toLocalFile(); // Properly handle file URLs
    }
    
    qDebug() << "Final load path:" << loadPath;
    
    // 加载图像 - use QImageReader for better format support
    QImageReader reader(loadPath);
    if (!reader.canRead()) {
        qWarning() << "Cannot read image:" << reader.errorString();
        return QImage();
    }
    QImage qImage = reader.read();
    if(qImage.isNull()) {
        qWarning() << "Failed to load image:" << loadPath;
        return QImage();
    }
    qDebug() << "Image loaded successfully. Size:" << qImage.size();

    // 转换为OpenCV格式
    cv::Mat src = qImageToMat(qImage);
    
    // 边缘检测处理
    cv::Mat edges;
    qDebug() << "Converting to grayscale...";
    cv::cvtColor(src, edges, cv::COLOR_BGR2GRAY);
    qDebug() << "Applying Gaussian blur...";
    cv::GaussianBlur(edges, edges, cv::Size(3,3), 0);
    qDebug() << "Running Canny edge detection...";
    cv::Canny(edges, edges, 50, 150);
    qDebug() << "Edge detection completed";
    
    // 转换回QImage格式
    return matToQImage(edges);
}

cv::Mat ImageProcessor::qImageToMat(const QImage &qImage)
{
    cv::Mat mat;
    switch(qImage.format()) {
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(qImage.height(), qImage.width(), CV_8UC4, 
                     const_cast<uchar*>(qImage.bits()), 
                     static_cast<size_t>(qImage.bytesPerLine()));
        cv::cvtColor(mat, mat, cv::COLOR_BGRA2BGR);
        break;
    default:
        QImage converted = qImage.convertToFormat(QImage::Format_RGB32);
        mat = cv::Mat(converted.height(), converted.width(), CV_8UC4, 
                     const_cast<uchar*>(converted.bits()), 
                     static_cast<size_t>(converted.bytesPerLine()));
        cv::cvtColor(mat, mat, cv::COLOR_BGRA2BGR);
        break;
    }
    return mat;
}

QImage ImageProcessor::matToQImage(const cv::Mat &mat)
{
    switch(mat.type()) {
    case CV_8UC1: {
        QImage image(mat.data, mat.cols, mat.rows, 
                    static_cast<int>(mat.step), 
                    QImage::Format_Grayscale8);
        return image.copy();
    }
    case CV_8UC3: {
        QImage image(mat.data, mat.cols, mat.rows, 
                    static_cast<int>(mat.step), 
                    QImage::Format_RGB888);
        return image.rgbSwapped().copy();
    }
    default:
        return QImage();
    }
}
